package com.ittianyu.bottomnavigationviewex;

import com.ittianyu.bottomnavigationviewex.item.BadgeItem;
import com.ittianyu.bottomnavigationviewex.item.BottomNavigationItem;
import com.ittianyu.bottomnavigationviewex.utils.AttrUtils;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;

import java.util.ArrayList;

public class BottomNavigationViewEx extends Component implements Component.TouchEventListener, Component.DrawTask {
    private static final int MIN_SIZE = 3;
    private static final int BACKGROUND_STYLE_DEFAULT = 0;
    private static final int BACKGROUND_STYLE_RIPPLE = 1;
    private static final int BACKGROUND_STYLE_STATIC = 2;
    private static final int MODE_SHIFTING_NO_TITLE = 3;
    private int mMode = MODE_DEFAULT;
    private static final int MODE_DEFAULT = 0;
    private static final int MODE_FIXED = 1;
    private static final int MODE_SHIFTING = 2;
    private static final int DEFAULT_ANIMATION_DURATION = 500;
    private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
    private int mRippleAnimationDuration = (int) (DEFAULT_ANIMATION_DURATION * 2.5);

    private boolean isFirst = true;
    private boolean needInit = true;
    private int height;
    private int selectWidth;
    private int unSelectWidth;
    private int offsetX;
    private int mElevation;
    private int iconMarginTop;
    private int iconSize;
    private int noTitleIconSize;
    private float textSize = 0;
    private int lastPosition;
    private int mCurrentPosition;

    private int downPostion = -1;
    private OnTabSelectedListener mTabSelectedListener;
    private int mActiveColor;
    private int mInActiveColor;
    private int mBackgroundColor;
    private int mItemClikcBg = 0x50000000;
    private int mBackgroundStyle = BACKGROUND_STYLE_DEFAULT;
    private Paint mPaint = new Paint();
    private Paint elevationPaint = new Paint();
    private Paint mOverPaint = new Paint();
    private Paint mTextPaint = new Paint();
    private boolean touchEffect;
    private boolean isShowCricle = true;
    private boolean isShowText = true;
    private boolean isHasText = true;
    private boolean isHasIcon = true;
    private boolean isDefaultTextsize = true;

    private int fixedTitleSizeActive;
    private int fixedTitleSizeInActive;

    private int shiftingTitleSizeActive;
    private int shiftingTitleSizeInActive;
    private int textCenterY;

    private ArrayList<BottomNavigationItem> mBottomNavigationItems = new ArrayList<>();

    private AnimatorValue changeAnimatorValue;
    private AnimatorValue overAnimatorValue;
    private float changePose = 1;
    private float overPose = 1;

    private Context mContext;

    public BottomNavigationViewEx(Context context) {
        this(context, null, null);
    }

    public BottomNavigationViewEx(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public BottomNavigationViewEx(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context, attrSet);
    }

    private void init(Context context, AttrSet attrSet) {
        this.mContext = context;
        mActiveColor = AttrUtils.getColorFromAttr(attrSet, "bnbActiveColor", Color.WHITE.getValue());
        mInActiveColor = AttrUtils.getColorFromAttr(attrSet, "bnbInactiveColor", Color.LTGRAY.getValue());
        mBackgroundColor = AttrUtils.getColorFromAttr(attrSet, "bnbBackgroundColor", Color.WHITE.getValue());

        mElevation = AttrUtils.getDimensionFromAttr(attrSet, "bnbElevation", AttrHelper.vp2px(8, context));
        mAnimationDuration = AttrUtils.getIntFromAttr(attrSet, "bnbAnimationDuration", DEFAULT_ANIMATION_DURATION);
        mMode = AttrUtils.getIntFromAttr(attrSet, "bnbMode", MODE_DEFAULT);
        mBackgroundStyle = AttrUtils.getIntFromAttr(attrSet, "bnbBackgroundStyle", BACKGROUND_STYLE_DEFAULT);
        touchEffect = AttrUtils.getBooleanFromAttr(attrSet, "bnbTouchEffect", false);

        height = AttrHelper.vp2px(56, context);
        iconMarginTop = (int) (height * 0.15);
        iconSize = AttrHelper.vp2px(24, context);
        noTitleIconSize = AttrHelper.vp2px(32, context);
        fixedTitleSizeActive = AttrHelper.vp2px(14, context);
        fixedTitleSizeInActive = AttrHelper.vp2px(12, context);
        shiftingTitleSizeActive = AttrHelper.vp2px(14, context);
        shiftingTitleSizeInActive = AttrHelper.vp2px(0, context);
        textCenterY = AttrHelper.vp2px(39, context);

        mPaint.setAntiAlias(true);
        mOverPaint.setAntiAlias(true);
        mTextPaint.setAntiAlias(true);
        setTouchEventListener(this);
        addDrawTask(this);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (isFirst) {
            isFirst = false;
            ComponentContainer.LayoutConfig layoutConfig = getLayoutConfig();
            layoutConfig.setMarginBottom(0);
            layoutConfig.height = height + mElevation;
            setLayoutConfig(layoutConfig);
        }

        if (mBottomNavigationItems != null && mBottomNavigationItems.size() > 0) {
            if (needInit) {
                needInit = false;

                if (mMode == MODE_SHIFTING) {
                    getMeasurementsForShiftingMode(getWidth(), mBottomNavigationItems.size());
                } else {
                    getMeasurementsForFixedMode(getWidth(), mBottomNavigationItems.size());
                }
            }
        }

        LinearShader gradient =
                new LinearShader(
                        new Point[] {new Point(0, 0), new Point(0, mElevation)},
                        new float[] {0f, 0.3f, 1f},
                        new Color[] {new Color(0x00000000), new Color(0x00000000), new Color(0x10000000)},
                        Shader.TileMode.CLAMP_TILEMODE);

        elevationPaint.setShader(gradient, Paint.ShaderType.LINEAR_SHADER);
        canvas.drawRect(new RectFloat(0, 0, component.getWidth(), mElevation), elevationPaint);

        if (mBackgroundStyle == BACKGROUND_STYLE_RIPPLE) {
            if (mCurrentPosition >= 0 && mCurrentPosition < mBottomNavigationItems.size()) {
                if (overPose == 1) {
                    mPaint.setColor(new Color(mBottomNavigationItems.get(mCurrentPosition).getActiveColor()));
                } else if (lastPosition >= 0 && lastPosition < mBottomNavigationItems.size()) {
                    mOverPaint.setColor(new Color(mBottomNavigationItems.get(mCurrentPosition).getActiveColor()));
                    mPaint.setColor(new Color(mBottomNavigationItems.get(lastPosition).getActiveColor()));
                }
            } else {
                mPaint.setColor(new Color(mActiveColor));
            }
        } else if (mBackgroundStyle == BACKGROUND_STYLE_STATIC) {
            if (mBackgroundColor == Color.WHITE.getValue()) {
                mPaint.setColor(new Color(0xff0000cd));
            } else {
                mPaint.setColor(new Color(mBackgroundColor));
            }
        } else {
            mPaint.setColor(new Color(mBackgroundColor));
        }

        canvas.drawRect(new RectFloat(0, mElevation, getWidth(), mElevation + height), mPaint);

        if (mBackgroundStyle == BACKGROUND_STYLE_RIPPLE && overPose != 1) {
            canvas.saveLayer(new RectFloat(0, mElevation, getWidth(), height + mElevation), mOverPaint);
            canvas.drawCircle(
                    getCurrentCenterX(mCurrentPosition, mCurrentPosition),
                    height / 2,
                    getWidth() * overPose,
                    mOverPaint);
            canvas.restore();
        } else if (mBackgroundStyle == BACKGROUND_STYLE_STATIC && overPose != 1) {
            if (isShowCricle) {
                int index = mBottomNavigationItems.size() - 1;
                if (mCurrentPosition == 0) {
                    canvas.saveLayer(new RectFloat(0, mElevation, selectWidth, height + mElevation), mOverPaint);
                } else if (mBottomNavigationItems.size() > 1 && mCurrentPosition == index) {
                    canvas.saveLayer(new RectFloat(0, mElevation, getWidth(), height + mElevation), mOverPaint);
                    canvas.saveLayer(
                            new RectFloat(getWidth() - selectWidth, mElevation, getWidth(), height + mElevation),
                            mOverPaint);
                } else {
                    float left = unSelectWidth * mCurrentPosition;
                    float right = selectWidth + unSelectWidth * mCurrentPosition;
                    canvas.saveLayer(new RectFloat(0, mElevation, getWidth(), height + mElevation), mOverPaint);
                    canvas.saveLayer(new RectFloat(left, mElevation, right, height + mElevation), mOverPaint);
                }
                Paint paint = new Paint();
                paint.setAntiAlias(true);
                paint.setColor(new Color(mItemClikcBg));
                canvas.drawCircle(
                        getCurrentCenterX(mCurrentPosition, mCurrentPosition),
                        height / 2,
                        unSelectWidth * 0.75f,
                        paint);
                canvas.restore();
            }
        }

        canvas.save();
        canvas.translate(offsetX, mElevation);

        for (int i = 0; i < mBottomNavigationItems.size(); i++) {
            BottomNavigationItem bottomNavigationItem = mBottomNavigationItems.get(i);
            int size = iconSize;

            if (mMode == MODE_SHIFTING_NO_TITLE || !isHasText) {
                size = noTitleIconSize;
            }
            float topOff = 0;
            int fiveVp = AttrHelper.vp2px(5, mContext);
            int twoVp = AttrHelper.vp2px(2, mContext);
            int zeroVp = AttrHelper.vp2px(0, mContext);

            if (mMode == MODE_SHIFTING || mMode == MODE_SHIFTING_NO_TITLE || !isHasText) {
                if (i != lastPosition && i != mCurrentPosition) {
                    topOff = fiveVp;
                } else if (i == mCurrentPosition) {
                    topOff = fiveVp + (zeroVp - fiveVp) * changePose;
                } else if (i == lastPosition) {
                    topOff = zeroVp + (fiveVp - zeroVp) * changePose;
                }
            } else {
                if (i != lastPosition && i != mCurrentPosition) {
                    topOff = twoVp;
                } else if (i == mCurrentPosition) {
                    topOff = twoVp + (zeroVp - twoVp) * changePose;
                } else if (i == lastPosition) {
                    topOff = zeroVp + (twoVp - zeroVp) * changePose;
                }
            }

            float centerX =
                    getCurrentCenterX(i, lastPosition)
                            + (getCurrentCenterX(i, mCurrentPosition) - getCurrentCenterX(i, lastPosition))
                                    * changePose;

            if (touchEffect && i == downPostion) {
                Paint circle = new Paint();
                circle.setColor(new Color(0x50000000));
                canvas.saveLayer(new RectFloat(0, mElevation, getWidth(), height + mElevation), mOverPaint);
                canvas.drawCircle(centerX, height / 2, selectWidth * 0.52f, circle);
            }

            PixelMap pixelMap = bottomNavigationItem.getInactiveIcon();

            if (mBackgroundStyle == BACKGROUND_STYLE_RIPPLE || mBackgroundStyle == BACKGROUND_STYLE_STATIC) {
                if (i == mCurrentPosition) {
                    mTextPaint.setColor(
                            new Color(
                                    bottomNavigationItem.getBackgroundColor() != 0
                                            ? bottomNavigationItem.getBackgroundColor()
                                            : getBackgroundColor()));
                    pixelMap = bottomNavigationItem.getBackgroundPixelMap();
                } else {
                    mTextPaint.setColor(
                            new Color(
                                    bottomNavigationItem.getInActiveColor() != 0
                                            ? bottomNavigationItem.getInActiveColor()
                                            : getInActiveColor()));
                    pixelMap = bottomNavigationItem.getInActivePixelMap();
                }
            } else {
                if (i == mCurrentPosition) {
                    mTextPaint.setColor(
                            new Color(
                                    bottomNavigationItem.getActiveColor() != 0
                                            ? bottomNavigationItem.getActiveColor()
                                            : getActiveColor()));
                    pixelMap = bottomNavigationItem.getActivePixelMap();
                } else {
                    mTextPaint.setColor(
                            new Color(
                                    bottomNavigationItem.getInActiveColor() != 0
                                            ? bottomNavigationItem.getInActiveColor()
                                            : getInActiveColor()));
                    pixelMap = bottomNavigationItem.getInActivePixelMap();
                }
            }

            if (pixelMap != null && isHasIcon) {
                RectFloat rectFloat = new RectFloat();
                rectFloat.left =
                        getCurrentCenterX(i, lastPosition)
                                + (getCurrentCenterX(i, mCurrentPosition) - getCurrentCenterX(i, lastPosition))
                                        * changePose
                                - size / 2;
                rectFloat.right =
                        getCurrentCenterX(i, lastPosition)
                                + (getCurrentCenterX(i, mCurrentPosition) - getCurrentCenterX(i, lastPosition))
                                        * changePose
                                + size / 2;

                rectFloat.top = iconMarginTop + topOff;
                rectFloat.bottom = iconMarginTop + topOff + size;
                mPaint.setColor(new Color(0xffffffff));
                canvas.drawPixelMapHolderRect(
                        new PixelMapHolder(pixelMap),
                        new RectFloat(0, 0, pixelMap.getImageInfo().size.width, pixelMap.getImageInfo().size.height),
                        rectFloat,
                        mPaint);
            }

            if ((mMode == MODE_SHIFTING || mMode == MODE_FIXED) && isHasText) {
                float defaultTextSize = 0;
                if ((mMode == MODE_SHIFTING || mMode == MODE_SHIFTING_NO_TITLE) && isShowText) {
                    if (i != lastPosition && i != mCurrentPosition) {
                        defaultTextSize = shiftingTitleSizeInActive;
                    } else if (i == mCurrentPosition) {
                        defaultTextSize =
                                shiftingTitleSizeInActive
                                        + (shiftingTitleSizeActive - shiftingTitleSizeInActive) * changePose;
                    } else if (i == lastPosition) {
                        defaultTextSize =
                                shiftingTitleSizeActive
                                        + (shiftingTitleSizeInActive - shiftingTitleSizeActive) * changePose;
                    }
                } else if ((mMode == MODE_FIXED && mBackgroundStyle == BACKGROUND_STYLE_STATIC) && isShowText) {
                    if (i != lastPosition && i != mCurrentPosition) {
                        defaultTextSize = shiftingTitleSizeInActive;
                    } else if (i == mCurrentPosition) {
                        defaultTextSize =
                                shiftingTitleSizeInActive
                                        + (shiftingTitleSizeActive - shiftingTitleSizeInActive) * changePose;
                    } else if (i == lastPosition) {
                        defaultTextSize =
                                shiftingTitleSizeActive
                                        + (shiftingTitleSizeInActive - shiftingTitleSizeActive) * changePose;
                    }
                } else {
                    if (i != lastPosition && i != mCurrentPosition) {
                        defaultTextSize = fixedTitleSizeInActive;
                    } else if (i == mCurrentPosition) {
                        defaultTextSize =
                                fixedTitleSizeInActive + (fixedTitleSizeActive - fixedTitleSizeInActive) * changePose;
                    } else if (i == lastPosition) {
                        defaultTextSize =
                                fixedTitleSizeActive + (fixedTitleSizeInActive - fixedTitleSizeActive) * changePose;
                    }
                }

                mTextPaint.setTextSize((int) defaultTextSize);
                float textWidth = mTextPaint.measureText(bottomNavigationItem.getText());
                float textHeight = mTextPaint.descent() - mTextPaint.ascent();
                if (isHasIcon) {
                    canvas.drawText(
                            mTextPaint,
                            bottomNavigationItem.getText(),
                            centerX - textWidth / 2,
                            textCenterY + textHeight / 2);
                } else {
                    canvas.drawText(
                            mTextPaint,
                            bottomNavigationItem.getText(),
                            centerX - textWidth / 2,
                            (float) (height * 0.6));
                }
            }

            if (bottomNavigationItem.getBadgeItem() != null && !bottomNavigationItem.getBadgeItem().isHidden()) {
                BadgeItem badgeItem = bottomNavigationItem.getBadgeItem();
                badgeItem.drawToCanvas(
                        canvas,
                        centerX,
                        height / 2 + topOff,
                        size / 2 + AttrHelper.vp2px(6, mContext),
                        -AttrHelper.vp2px(16, mContext),
                        AttrHelper.vp2px(12, mContext),
                        AttrHelper.vp2px(1, mContext));
            }
        }
        canvas.restore();
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        float touchX = getTouchX(touchEvent, 0);
        float touchY = getTouchY(touchEvent, 0);

        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                if (mBottomNavigationItems != null && mBottomNavigationItems.size() > 0) {
                    downPostion = getPostionFromX(touchX);
                    if (touchEffect) {
                        if (overAnimatorValue == null || !overAnimatorValue.isRunning()) {
                            invalidate();
                        }
                    }
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                if (downPostion != -1) {
                    if (getPostionFromX(touchX) == downPostion && touchY >= 0 && touchY <= height) {
                        if (mBottomNavigationItems != null && mBottomNavigationItems.size() > downPostion) {
                            choose(downPostion);
                            downPostion = -1;
                            if (touchEffect) {
                                if (overAnimatorValue == null || !overAnimatorValue.isRunning()) {
                                    invalidate();
                                }
                            }
                        }
                    }
                }
                break;

            case TouchEvent.POINT_MOVE:
                if (downPostion != -1) {
                    if (getPostionFromX(touchX) != downPostion || touchY < 0 || touchY > height) {
                        downPostion = -1;
                        if (mBottomNavigationItems != null && mBottomNavigationItems.size() > 0) {
                            if (touchEffect) {
                                if (overAnimatorValue == null || !overAnimatorValue.isRunning()) {
                                    invalidate();
                                }
                            }
                        }
                    }
                }
                break;
            default:
                break;
        }
        return true;
    }

    private float getTouchX(TouchEvent touchEvent, int index) {
        float x = 0;
        if (touchEvent.getPointerCount() > index) {
            int[] xy = getLocationOnScreen();
            if (xy != null && xy.length == 2) {
                x = touchEvent.getPointerScreenPosition(index).getX() - xy[0];
            } else {
                x = touchEvent.getPointerPosition(index).getX();
            }
        }
        return x;
    }

    private float getTouchY(TouchEvent touchEvent, int index) {
        float y = 0;
        if (touchEvent.getPointerCount() > index) {
            int[] xy = getLocationOnScreen();
            if (xy != null && xy.length == 2) {
                y = touchEvent.getPointerScreenPosition(index).getY() - xy[1];
            } else {
                y = touchEvent.getPointerPosition(index).getY();
            }
        }
        return y;
    }

    private int getPostionFromX(float touchX) {
        int x = offsetX;
        if (mBottomNavigationItems != null && mBottomNavigationItems.size() > 0) {
            for (int i = 0; i < mBottomNavigationItems.size(); i++) {
                if (mCurrentPosition == i) {
                    x += selectWidth;
                } else {
                    x += unSelectWidth;
                }
                if (x >= touchX) {
                    return i;
                }
            }
        }
        return -1;
    }

    private void getMeasurementsForFixedMode(int screenWidth, int items) {
        int width = AttrHelper.vp2px(120, mContext);

        int itemWidth = screenWidth / items;

        if (itemWidth > width) {
            itemWidth = width;
        }
        unSelectWidth = itemWidth;
        selectWidth = itemWidth;
        offsetX = (screenWidth - itemWidth * items) / 2;
    }

    private void getMeasurementsForShiftingMode(int screenWidth, int items) {
        int minWidth = AttrHelper.vp2px(64, mContext);
        int maxWidth = AttrHelper.vp2px(96, mContext);
        double minPossibleWidth = minWidth * (items + 0.5);
        double maxPossibleWidth = maxWidth * (items + 0.75);

        int itemWidth;
        int itemActiveWidth;

        if (screenWidth < minPossibleWidth) {
            itemWidth = (int) (screenWidth / (items + 0.5));
            itemActiveWidth = (int) (itemWidth * 1.5);
        } else if (screenWidth > maxPossibleWidth) {
            itemWidth = maxWidth;
            itemActiveWidth = (int) (itemWidth * 1.75);
        } else {
            double minPossibleWidth1 = minWidth * (items + 0.625);
            double minPossibleWidth2 = minWidth * (items + 0.75);

            itemWidth = (int) (screenWidth / (items + 0.5));
            itemActiveWidth = (int) (itemWidth * 1.5);

            if (screenWidth > minPossibleWidth1) {
                itemWidth = (int) (screenWidth / (items + 0.625));
                itemActiveWidth = (int) (itemWidth * 1.625);
                if (screenWidth > minPossibleWidth2) {
                    itemWidth = (int) (screenWidth / (items + 0.75));
                    itemActiveWidth = (int) (itemWidth * 1.75);
                }
            }
            unSelectWidth = itemWidth;
            selectWidth = itemActiveWidth;
            offsetX = (screenWidth - (itemActiveWidth + itemWidth * (items - 1))) / 2;
        }
    }

    private int getCurrentCenterX(int index, int selectIndex) {
        int x = 0;
        if (mBottomNavigationItems != null && mBottomNavigationItems.size() > 0) {
            for (int i = 0; i < mBottomNavigationItems.size() && i <= index; i++) {
                if (index == i) {
                    if (selectIndex == i) {
                        x += selectWidth / 2;
                    } else {
                        x += unSelectWidth / 2;
                    }
                } else {
                    if (selectIndex == i) {
                        x += selectWidth;
                    } else {
                        x += unSelectWidth;
                    }
                }
            }
        }
        return x;
    }

    private void choose(int targetPosition) {
        if (targetPosition == mCurrentPosition && mTabSelectedListener != null) {
            mTabSelectedListener.onTabReselected(mCurrentPosition);
        }

        if (targetPosition == mCurrentPosition
                || mBottomNavigationItems == null
                || targetPosition >= mBottomNavigationItems.size()) {
            return;
        }

        if (changeAnimatorValue != null && changeAnimatorValue.isRunning()) {
            return;
        }

        if (overAnimatorValue != null && overAnimatorValue.isRunning()) {
            overAnimatorValue.stop();
        }

        if (mTabSelectedListener != null) {
            mTabSelectedListener.onTabSelected(downPostion);
            mTabSelectedListener.onTabUnselected(mCurrentPosition);
        }

        lastPosition = mCurrentPosition;
        mCurrentPosition = targetPosition;
        changePose = 0;
        overPose = 0;

        if (mBottomNavigationItems.get(mCurrentPosition) != null
                && mBottomNavigationItems.get(mCurrentPosition).getBadgeItem() != null
                && mBottomNavigationItems.get(mCurrentPosition).getBadgeItem().isHideOnSelect()
                && !mBottomNavigationItems.get(mCurrentPosition).getBadgeItem().isHidden()) {
            mBottomNavigationItems.get(mCurrentPosition).getBadgeItem().hide();
        }

        if (changeAnimatorValue == null) {
            changeAnimatorValue = new AnimatorValue();
            changeAnimatorValue.setDuration(mAnimationDuration);
            changeAnimatorValue.setCurveType(Animator.CurveType.LINEAR);
            changeAnimatorValue.setValueUpdateListener(
                    new AnimatorValue.ValueUpdateListener() {
                        @Override
                        public void onUpdate(AnimatorValue animatorValue, float v) {
                            changePose = v;
                        }
                    });
        }
        if (overAnimatorValue == null) {
            overAnimatorValue = new AnimatorValue();
            overAnimatorValue.setDuration(mRippleAnimationDuration);
            overAnimatorValue.setCurveType(Animator.CurveType.LINEAR);
            overAnimatorValue.setValueUpdateListener(
                    new AnimatorValue.ValueUpdateListener() {
                        @Override
                        public void onUpdate(AnimatorValue animatorValue, float v) {
                            overPose = v;
                            getContext()
                                    .getUITaskDispatcher()
                                    .asyncDispatch(
                                            new Runnable() {
                                                @Override
                                                public void run() {
                                                    invalidate();
                                                }
                                            });
                        }
                    });
        }

        changeAnimatorValue.start();
        overAnimatorValue.start();
    }

    public interface OnTabSelectedListener {
        void onTabSelected(int position);

        void onTabUnselected(int position);

        void onTabReselected(int position);
    }

    public void clearAll() {
        mBottomNavigationItems.clear();
    }

    public void initialise() {
        if (mMode == MODE_DEFAULT) {
            if (mBottomNavigationItems.size() <= MIN_SIZE) {
                mMode = MODE_FIXED;
            } else {
                mMode = MODE_SHIFTING;
            }
        }

        if (mBackgroundStyle == BACKGROUND_STYLE_DEFAULT) {
            if (mMode == MODE_FIXED) {
                mBackgroundStyle = BACKGROUND_STYLE_DEFAULT;
            } else if (mMode == MODE_SHIFTING) {
                mBackgroundStyle = BACKGROUND_STYLE_STATIC;
            }
        }
        needInit = true;
        invalidate();
    }

    public BottomNavigationViewEx addItem(BottomNavigationItem item) {
        if (mBottomNavigationItems == null) {
            mBottomNavigationItems = new ArrayList<>();
        }
        item.setupPixelMap(this, AttrHelper.vp2px(32, mContext));
        mBottomNavigationItems.add(item);
        return this;
    }

    public BottomNavigationViewEx setBackgroundColor(int backgroundColor) {
        mBackgroundColor = backgroundColor;
        return this;
    }

    public int getBackgroundColor() {
        return mBackgroundColor;
    }

    public BottomNavigationViewEx setIconVisibility(boolean visibility) {
        isHasIcon = visibility;
        isShowText = false;
        return this;
    }

    public BottomNavigationViewEx setTextVisibility(boolean visibility) {
        if (!visibility) {
            isHasText = visibility;
        }
        return this;
    }

    public BottomNavigationViewEx enableAnimation(boolean enable) {
        isShowCricle = enable;
        return this;
    }

    public BottomNavigationViewEx enableShiftingMode(boolean enable) {
        if (enable) {
            mMode = MODE_SHIFTING;
        } else {
            mMode = MODE_FIXED;
            mBackgroundStyle = BACKGROUND_STYLE_STATIC;
        }
        return this;
    }

    public BottomNavigationViewEx setShowAllText(boolean show) {
        isShowText = show;
        return this;
    }

    @Deprecated
    public BottomNavigationViewEx noShiftingModeAndShowAllText() {
        mMode = MODE_FIXED;
        mBackgroundStyle = BACKGROUND_STYLE_STATIC;
        isShowText = false;
        return this;
    }

    public int getCurrentItem() {
        return mCurrentPosition;
    }

    public int getMenuItemPosition(BottomNavigationItem item) {
        if (mBottomNavigationItems != null && mBottomNavigationItems.size() > 0) {
            int position = -1;
            for (int index = 0; index < mBottomNavigationItems.size(); index++) {
                if (mBottomNavigationItems.get(index).equals(item)) {
                    position = index;
                }
            }
            return position;
        } else {
            return -1;
        }
    }

    public BottomNavigationViewEx setCurrentItem(int position) {
        mCurrentPosition = position;
        if (mTabSelectedListener != null) {
            mTabSelectedListener.onTabSelected(position);
        }
        invalidate();
        return this;
    }

    public OnTabSelectedListener getOnNavigationItemSelectedListener() {
        return this.mTabSelectedListener;
    }

    public BottomNavigationViewEx setTabSelectedListener(OnTabSelectedListener tabSelectedListener) {
        this.mTabSelectedListener = tabSelectedListener;
        return this;
    }

    public PixelMap getIconAt(int position) {
        BottomNavigationItem bottomNavigationItem = mBottomNavigationItems.get(position);
        return bottomNavigationItem.getInactiveIcon();
    }

    public int getItemCount() {
        return mBottomNavigationItems.size();
    }

    public int getItemHeight() {
        return height;
    }

    public String getLargeLabelAtText(int position) {
        BottomNavigationItem bottomNavigationItem = mBottomNavigationItems.get(position);
        return bottomNavigationItem.getText();
    }

    // 设置指定位置标签文本
    public BottomNavigationViewEx setLargeLabelAtText(String text, int position) {
        if (mBottomNavigationItems != null && mBottomNavigationItems.size() > 0) {
            BottomNavigationItem bottomNavigationItem = mBottomNavigationItems.get(position);
            bottomNavigationItem.setText(text);
        }
        return this;
    }

    public BottomNavigationViewEx setIconSize(int iconSize) {
        if (mMode == MODE_SHIFTING_NO_TITLE) {
            this.noTitleIconSize = iconSize;
        } else {
            this.iconSize = iconSize;
        }
        return this;
    }

    public BottomNavigationViewEx setTextSize(float textSize) {
        isDefaultTextsize = false;
        this.textSize = textSize;
        return this;
    }

    public ArrayList getBottomNavigationItemViews() {
        return mBottomNavigationItems;
    }

    public BottomNavigationItem getBottomNavigationItemView(int position) {
        if (position >= 0 && position < mBottomNavigationItems.size()) {
            return mBottomNavigationItems.get(position);
        }
        return null;
    }

    public BottomNavigationViewEx setActiveColor(int activeColor) {
        mActiveColor = activeColor;
        return this;
    }

    public BottomNavigationViewEx setInActiveColor(int inActiveColor) {
        mInActiveColor = inActiveColor;
        return this;
    }

    public BottomNavigationViewEx setItemClickBg(int color) {
        this.mItemClikcBg = color;
        return this;
    }

    public int getInActiveColor() {
        return mInActiveColor;
    }

    public int getActiveColor() {
        return mActiveColor;
    }

    public BottomNavigationViewEx setupWithViewPager(PageSlider pageSlider) {
        if (pageSlider != null) {
            pageSlider.addPageChangedListener(
                    new PageSlider.PageChangedListener() {
                        @Override
                        public void onPageSliding(int i, float v, int i1) {}

                        @Override
                        public void onPageSlideStateChanged(int i) {}

                        @Override
                        public void onPageChosen(int position) {
                            setCurrentItem(position);
                        }
                    });
        }

        return this;
    }
}
